APC Action Applications - Home Page

Frequently Asked Questions v2

 

Answers for: Developer

0. How to create an aa in an alternate language?
1. How to make item url shorter?
2. What are the plans for the FAQs?
3. How to push/pull data into/from database
4. How should I return errors
5. How to create new alias function?
6. How to create a new Action Aplication
7. How to edit a file and check it back into the distribution
8. What are the CVS branch version numbers of APC-AA and how do I check out a specific versio
9. Can I call apc-aa item-manager from other php3 code
10. How does file upload work
11. Language files with Mini Gettext
12. How to create new module?
13. What coding standards should I follow
14. How to debug Action Apps code and sites?
15. POST to .shtml
16. How do Tagged IDs work

If you want to translate the ActionApps to another language, you can look at:

Why are slice IDs and item IDs so long?
Would it be possible to make them shorter?

The 32-digits hexadecimal IDs are quite standard in MySQL/PHP - see uniqid() and md5() functions. These identifiers are intended to be unique worldwide so that each item has an unique ID regardless of where it is stored, such as on Econnect's server or on Colnodo's. This feature helps us in cross-server feeding.

Internally (within the database) the IDs are stored as 16-character strings (for disk-space savings and a little better performance of the database), but this is only important for developers.

Because of long URLs, I made short_id in v1.8 - so that the auto-incremented short IDs are used by default. The URL for an item is now, for example:

http://kalendar.ecn.cz/index.shtml?AA_SL_Session=44ca275c691 842965745f90ab9aee24e&x=27968

or, even better:

http://kalendar.ecn.cz/index.shtml?x=27968

Next suggested steps for the upgrading the FAQ:

  1. Fix old links within fulltext.
  2. Categorize and fix grammer in all articles
  3. Get popular collections view working (uses related items) and ask key users to submit their favorite collections.
  4. Add more content from email archives and personal notes.
  5. Add email alert feature
  6. Allow for editing on site for logged in users.

Also need to get other language views and content going (e.g. Spanish).

I also plan to create a Requested Feautre slice in the near future that will use the same alert login.

Some help with updating FAQ content would be most appreciated. :^)

 - JD- - - --

External SQL query should look like:

SELECT * FROM item, content
  WHERE item.id = content.item_id                // to join the tables
      AND item.id = 'hey67s[o0-78z._d'           // 16 characters long packed id
                                                 // see util.php3 - q_pack_id()
      AND content.field_id = 'headline........';

This SQL query select all fields from item table (where are stored just the most common item fields - id, short_id, slice_id, status_code, post_date, publish_date, expiry_date, highlight, posted_by, edited_by, last_edit, display_count, flags, disc_count, disc_app, externally_fed) plus the content of 'headline........' field from content table (will be in content.text field). You can change 'headline........' to any field id, of course, just like 'category.......1' or 'source.........1'. Also you can use short_ids as well to identify the item.

Database structure used for items

Data for an item is not stored in one table, as it is obvious and as you probably expect. Data are divided to two tables - item and content. Item table stores the common fields, which is requiered for each item. All other columns are sored in related table content (relation 1:N). The content table is quite easy - item_id, field_id, number, text, flag. Each row holds contents (in 'text' or 'number' filed) of one field (identified by field_id - like 'headline........') for one item (identified by 'item_id' - related to id in 'item' table).

Such, say 'virtual table database structure' or 'object oriented database' allows to store items of any number of fields. It also allows to store multiple values for one field (you just add a row with the same item_id and field_id).

More complicated SQL query, which contain more fields from content table could look like:


SELECT item.*, c1.text, c2.text FROM item, content as c1, content as c2
  WHERE item.id = c1.item_id       // to join the tables
      AND item.id = c2.item_id       // to join the tables
      AND item.short_id = '13432' // we can use short id
      AND c1.field_id = 'headline........';
      AND c2.field_id = 'full_text.......';

(this approach is used in main query function of AA - QueryIds() in include/searchlib.php3)

To select all extended fields for the item use:


SELECT * FROM content WHERE item_id = 'hey67s[o0-78z._d';

The data for field are stored in 'text' field of content table or in 'number' depending on 'text_stored' flag in 'field' table.

Item data manipulationg functions (data API)

It is important to know how the data are stored in database, but if you want to write some feature to AA, it is strongly recomended not to use direct database access, but rather use three main data API function to access data (especially for storing data into AA database). The functions are independent on database structure behind and it takes care about feeding, clearing the cache and other stuff.

Main AA data API functions are:


function QueryIDs($fields, $slice_id, $conds, $sort="", $group_by="",
                  $type="ACTIVE", $slices="", $neverAllItems=0,
                  $restrict_ids=array() )
  - stored in include/searchlib.php3

function GetItemContent($ids, $use_short_ids=false)
  - stored in include/util.php3

function StoreItem( $id, $slice_id, $content4id, $fields, $insert,
                             $invalidatecache=true, $feed=true )
  - stored in include/itemfunc.php3

By QueryIDs function you will get array of IDs of items based on your conditions, possiblly sorted. Input conditions are stored in array which you already know from design of searchform (conds[0][publish_date....]=...). This function allows you to get IDs based on any number of conditions. Also it is completely database independent, so you need not to know, which field is stored in item table and which is stored in content table.

The content of an item you will get by GetItemContent function. As input parameter use the IDs of the items you want to get (possibly obtained by QueryIDs). The items are then returned in array structure, which is good to know about, because all data manipulation functions in AA uses this structure to access the item data. This structure is also used as parameter to StoreItem function.

Item data structure

Abstract Data Structure for data manipulation in AA (returned by GetItemContent function):


$content[<unpacked_item_id>][<field_id>)][<alternative>][value|flag]

where
<unpacked_item_id>
is 32 characters long hexadecimal id of item (structure holds data for more than one item, generaly)
<field_id>
is field id as you know it from Admin -> Fields page of AA admin interface ( like 'headline........', 'url............2', ...)
<alternative>
is number used for storing multiple values for the same field. Obviously there is only '0' index, but for field, where we store multiple categories (for example) it will utilize indexes '0', '1' ,... up to number of selected categories for the item
<value
is probably what you care about - it is content of the field like 'An article title' or 1092928827 or <fulltext of item>
flag>
special flags for the content - if the content is HTML formatted, ... The list of possible flags follows (defined in include/constants.php3)

            define( "FLAG_HTML", 1 );      # content is in HTML
            define( "FLAG_FEED", 2 );      # item is fed
            define( "FLAG_FREEZE", 4 );    # content can't be changed
            define( "FLAG_OFFLINE", 8 );   # off-line filled
            define( "FLAG_UPDATE", 16 );   # content should be updated
                                                     # if source is changed
                                                     #   (after feeding)
      

So, to access content of 'headline.........' field for item number 5e72be7289a0be63820a8723837ce21a you can type:


$text = $content['5e72be7289a0be63820a8723837ce21a']['headline........'][0]['value'];

For inserting or changing data of an item you just fill the structure described above and call the StoreItem function.

Error returns in AA are not consistent, there is a general, low priority, task to clean up the code as we work on it.

In general use the $err array to return errors.

Some specific examples follow, please add others here.

Each of the functions: insert_fnc_xxx sets for example

$err[image.....1] => "Wrong type of file"

If you find no alias function is good enough for you, you can write your own. function. The alias functions are stored in include/item.php3 file and its names begins with f_ (but we can name it as g_* or such, as well) and they are three letters long (just like f_a()).

All you have to do for new function is:

  1. Write your own function in item.php3 (say f_9()).
  2. Add description of the function into param wizard definition file include/constants_param_wizard.php3 (structure described inside this file)
  3. Add human readable messages into include/en_param_wizard_lang.php3 language file.

  4. Edit the FAQ item on Alias function paramaters

If you find, that the new alias function is very proprietary (it is unusable for other people, you can create file /include/usr_aliasfnc.php3, which is automaticaly included to code (if exists). There you can define your own alias functions. The function name must be prefixed by 'usr_' prefix. The function have three parameters:


The example listing of /include/usr_aliasfnc.php3 (the file should not be committed to CVS, because it is very proprietary and the content should not be shared between installations):

<?php //usr_aliasfnc.php3  

/** Prints czech date (for Ekolist pages)
* @param columns - array of all field values for all ifelds in current item
* @param col - fileld id of field, for which the alias is defined
* @param param - possibly parameters to alias function passed in alias definition parameter (usr_cz_date:parameter)
*/
function usr_cz_date($columns, $col, $param="") {
$dte = $columns[$col][0][value];
$month = array( 1 => "ledna", "unora", "brezna", "dubna", "kvetna", "cervna", "cervence", "srpna", "zari", "rijna", "listopadu", "prosince");
$weekday = array("nedele","pondeli","utery","streda","ctvrtek","patek","sobota");
$m = $month[ date("n", $dte)];
$end = ( !$param ? "" : " (". $weekday[ date("w", $dte) ]. ")");
return date("j", $dte) .". $m ". date("Y", $dte). $end;
}
?>

Such alias function can be called by defining new alias for some field. Just define alias name (as obvious), alias function should be "f_u - user function" and the parameter should be the name of the function ("usr_cz_date" in our example). It is possible to pass parameters to the function. The parameters are separated by colon (usr_cz_date:parameters).

The applications in v1.5+ can be created quite easy.

  1. Choose a slice and create the set of fields you want to have in the new application.

  2. For these fields change the default values, help texts, names, priorities, aliases, etc. in the admin interface ("Admin" -> "Main settings - Fields").

  3. Change the design of the fulltext view, list item view and possibly the admin view ("Admin" -> "Design - Fulltext", "Admin" -> "Design - Index", "Admin" -> "Design - Item Manager")

  4. Test the new slice, whether it is working O.K.

  5. Add a new slice based on this one (not a template, but a slice)

  6. Mark the new slice as a Template ("Admin" -> "Main settings - Slice") - to do this you must be the superadministrator (four stars).

To edit a file, you should work on a copy of the full APC-AA distribution, make changes and then check back the changed files

To check out the whole of apc-aa into some directory or other, you need to do it differently from the standard installation instructions if you plan on editing files.

The first time you use a particular CVS host you need to do ....

$ ssh yourusername@cvs.apc-aa.sourceforge.net

It should log you in, and straight out again (accept the host key if it asks you to)

$ export CVS_RSH=ssh #for bash for example
or
setenv CVS_RSH ssh # for tcsh for example
$ cvs -z3 -d:ext:yourusername@cvs.apc-aa.sourceforge.net:/cvsroot/apc-aa co apc-aa
yourusername@cvs.apc-aa.sourceforge.net's password:

If it doesn't ask for a password, but you get an error about connection refused its probably because it didn't see the CVS_RSH environment variable.

Edit the file, then

If the file is not already in the CVS repository, for example, because you have created a new file, then first add it to CVS with

$ cvs add myfile.htm

then upload with for example

$ cvs commit myfile.htm

Make sure to put in a useful comment when prompted by CVS.

Note, Its best NOT to do a plain

$ cvs commit

As this will commit files that you probably don't want to, especially config.php3

If you get the error:

Could not chdir to home directory /home/users/y/yo/yourusername: No such file or directory
cvs [server aborted]: can't chdir(/home/users/y/yo/yourusernameNo such file or directory

Then you need the ssh trick.

You can't use pserver: to check the files out, if you are going to commit them back again.

There are two branches, currently (9 Jan 2001) these numbers are

(main) developer 2.1.0
stable 2.0.1

Production systems will probably want to work with 2.0.1, although 2.1.0 is fairly stable.

In theory, to discover which version you are using, look in "CHANGES", for example apc-aa.sourceforge.net/aa/CHANGES shows that Sourceforge is still running the stable branch, but note that CHANGES is frequently NOT updated to show the version number of the developer version, and the current developer version shows the same version 2.0.1 with just a few more dated changes.

If you check out the default method:

cvs -z3 -d:ext:yourusername@cvs.apc-aa.sourceforge.net:/cvsroot/apc-aa -r2_0_1 co apc-aa
OR
cvs -d:pserver:anonymous@cvs.apc-aa.sourceforge.net:/cvsroot/apc-aa co -rv2_0_1 apc-aa

you will get the developer branch, but

cvs -z3 -d:ext:yourusername@cvs.apc-aa.sourceforge.net:/cvsroot/apc-aa co apc-aa
OR
cvs -d:pserver:anonymous@cvs.apc-aa.sourceforge.net:/cvsroot/apc-aa co apc-aa

Note that you cannot assume that different branches will run with the same Database.

In particular to upgrade from 2.0.1 to 2.1.0 you need to run sql_update.php3 to upgrade the database fields.

There are several recent (Mar 2002) changes to make it easier to call apc-aa modules, especially the item manager, from php code.

Sample code to call admin/index.php3 (item manager) from outside.

file: apc-aa/sample/itemmanager.php3
(this need to stay same level of folder with apc-aa/admin/ )

<?PHP
# parameter
# project_id - slice id for project slice.
#
# Usage:
# http://host.name/apc-aa/sample/itemmanager.php3&project_id=<slice id>
# <slice id> : slice id to be open ....
# optional parameter:
# Tab - this is for admin/index.php3 to select Table.
# ="app" - Active bin (default)
# ="appb" - Pending bin
# ="appc" - Expired
# ="hold" - Hold bin
# ="trash" - Trash
#
# AA_CP_Session - session id
#
require "../include/init_page.php3";
// this check AA_CP_Session and open login prompt and call me again.
// also it sets slice_id, is session is already there.


if( isset( $sess ) )
page_close(); // this will store session variables in database.



// === prepair parameters to call admin/index.php3 ===


// use change_id if we open the slice 1st time.
if ($project_id == $slice_id)
$slice_param = "&slice_id=$project_id"; // we may not need this.
else
$slice_param = "&change_id=$project_id";


// table to open (active,trash,hold,expire,pending...)
$tab_param = $Tab ? ("&Tab=".$Tab) : "";


// filter parameter from apc-aa/admin/index.php3
$filter_param = (!$admin_order)? "" :
"&admin_order=$admin_order".
"&admin_order_dir=$admin_order_dir".
"&admin_search=$admin_search".
"&admin_search_field=$admin_search_field";


// parametere for scroller -- set by admin/index.php3 (at callback)
$scroller_param="";
if ($scr_st3_Mv) $scroller_param .= "&scr_st3_Mv=$scr_st3_Mv";
if ($scr_st3_Go) $scroller_param .= "&scr_st3_Go=$scr_st3_Go";


$debug_param = $debug ? ("&debug=$debug") : "";


// parameter to call myself from admin/index.php3 (admin/index.php3 will call me back)
$my_param=
"AA_CP_Session=$AA_CP_Session".
"&project_id=$project_id".
"&projects_item=$projects_item".
$tab_param.
$debug_param;

$MY_URL=urlencode($PHP_SELF."?".$my_param); // &return_url=.... for itemedit.php3, etc.

// So, all parameter to call admin/index.php3 is prepaired we write the page.
?>
<?PHP // -- showing Project Tasks (a slice made from "Project Tasks (template)" )
// -- now , we are using ItemManager of APC-AA as our ItemManger (not slice.php3 with index view) $pts_item_manager = "http://localhost/apc-aa/admin/index.php3". "?AA_CP_Session=$AA_CP_Session". $slice_param. $tab_param. $scroller_param. "&bodyonly=1".
"&action_selected=1".
"&sort_filter=1".
"&return_url=$MY_URL".
$debug_param. ""; include $pts_item_manager; ?>
# action_select=1 turns off "Feed selected" and "View selected"
# sort_filter=1 turns off the sort line
# scr_st3_Mv and scr_st3_Go can be set to work with the scroller
All configuration options are in config.php3:

define("IMG_UPLOAD_MAX_SIZE", "400000"); # max size of file in picture uploading
define("IMG_UPLOAD_URL", "http://work.ecn.cz/img_upload/");
define("IMG_UPLOAD_PATH", "/data/www/htdocs/work.ecn.cz/img_upload/");
define("IMG_UPLOAD_TYPE", "image/*");
define("IMG_UPLOAD_DIR_MODE", 508); # mkdir perms (508 = 0774 in octal, but
# octal value in constant don't work)

When you submit first item with image in the slice, AA will create new subdirectory under the IMG_UPLOAD_PATH directory. The name of this directory is the slice id. In this example we can expect the directories like:

/data/www/htdocs/work.ecn.cz/img_upload/f4c90ee8ef46cd6fa0a4521c61a28f4f
/data/www/htdocs/work.ecn.cz/img_upload/5d2b4ed6778fe3ac6db6ec74ceee650d

The directories are created with IMG_UPLOAD_DIR_MODE mask.

The image upload function is quite easy and you can find it in include/itemfunc.php3 file - function insert_fnc_fil().

(c) Jakub Adámek, Econnect, January 2003

Since January 17 2003 AA is using the mini-gettext language environment. The language files are in the directory include/lang/.

Each file is connected with one language and a series of PHP scripts. At run-time, you can only use one file for translations at a time, but you can change freely between files by using the bind_mgettext_domain() function in include/mgettext.php3.

The files are maintained by people — translators and by the PHP function xmgettext() in misc/mgettext/xmgettext.php3. Translators add new translations and xmgettext() adds new strings to be translated which it finds in the source files.

Notes for Translators

To add new translations, you only need to find empty strings "" in your language files, e.g. $_m["not yet translated"] = "". Please mind some following notes.

The language files are regular PHP files, you must not break the syntax. You must not change the ID string in _m["..."]. Even if it contains bad English, it may be changed only in the source code, not in the language file. There is also an English translations file, thus small changes may take place there.

You must follow the PHP syntax for strings, using \" and \$ instead of " and $. You must quote the translation with "". (You might quote it with single quotes as well, but next time xmgettext() will be run, it will reformat all strings to double quotes.)

Each language string is preceded by links to source code where it is used. If you are not sure how to translate a string, go to the source code and have a look. Some language strings contain parameters %1,%2 etc. which will be replaced by some variable content at run-time. Place the parameters appropriately in the translation.

The file begins with a list of "Unused messages" which are there only for your convenience so that you may use the text for the new translations if necessary. You can freely delete any unused messages.

Notes for Developers

Have a look at Notes for Translators. The explanation of using mini-gettext in code follows.

The simple syntax: A string becomes language string by enclosing into _m(" "), e.g.

_m("any string").

It is better to create long strings than to concatenate short ones, because translators may easier understand the meaning.

The parametrized syntax: You must not use variables in language strings. But you can use parameters %1,%2,... with the syntax of

_m("... %1 ... %3 ... %2", array ($param1,$param2,$param3)), e.g.

_m("Click on %1 to get more help.", array ($url)) or
_m("Error %1 in file %2 on line %3", array ($err,$file,$line)).

Always use the array() even when using only one parameter %1.

To update language files, use xmgettext(). Call it by the misc/mgettext/index.php3 script. Have a look on particular settings in the script. You need to provide read-write access for PHP to language files in order to update them. Copy them into another directory (I used ../php_rw/lang, i.e. not a subdir of the AA installation), set permissions, run xmgettext and copy the updated files back. A side remark: If you don't like this overhead, just remember which overhead it took to create and copy all the L_ language constants to new_news_lang.php3 ...

One more thing to take care of is the run-time switching between languages. If you fill in some include file a global variable with translated strings and than change language, it will remain in the old language. You must create a function returning the variable to avoid this.

Hope you will like my mgettext solution,

Jakub

What is a module?
-----------------
You probably know slices - a part of database with its admin interface
which is able to manipulate with items/articles. The slices are very
configurable, so it can hold news or events as well as database of
links, organizations or members. Slices are great for presenting tabular
data of any type. On the oher hand, there are many cases, where we need
comletely different data structure, behavior of admin interface or
presentation layer. As example we could mention polls, petitions, ...

Because users of AA (including us) wants to manage such data in the same
(ActionApps) environment, we have to find the way, how to incorporate
such data administration into AA. The answer is modules.

It's hard to explain what modules are and how you can create it, because
the is no good example of working module, rihgt now. In fact, there are
two modules - module 'jump' and module 'site'. The Jump module is too
easy (it allows you just to jump to specified page of specified slice in
admin interface) and the site module is too complex and it is not fully
integrated into AA. That's why it is not commited into CVS at this moment.

What the module allows
----------------------
- allows you to create different admin interface for the module data
(You can replace Item Manager and Slice Admin by your own admin pages,
including left menu bar, ...
- allows you to use your own database tables
- allows you to use your own permissions in new module (there is general
permission system with standardized perm API defined, which provides
abstract layer for functions like AddPermObject, AddPermUser,... -
such functions then operates in backroud with LDAP, SQL, ...)

How modules apears to user in AA admin interface
------------------------------------------------
All modules which belogns to logged user are listed in 'Module
selectbox' which you uses for selection of slices, right now (well known
'Switch to' selectbox). The idea is, that in this selectbox then user
switch to administration of news of site XY, to administration of events
of site XY, and to administration of polls for this site. In fact the
slices now became just one of the modules incorporated into AA environment.

When user selects another module type in Module selectbox, then upper
navigation bar will be changed just slightly. User will see probably no
'Item Manager' as well as 'Slice Admin' menu options. (S)he will see
'Poll Manager' and 'Poll Admin', or maybe just Poll Manager (if we speak
about poll module as example).

How to create new module in APC Action Apps
-------------------------------------------
Basic steps, which is needed for module creation are:

1) copy the modules/module_TEMPLATE to the new directory and name it by
the name of module (just for clarity) (modules/poll for example).

2) open /include/constants.php3 and add new module in the $MODULES
array.

3) create database tables for the module and add the definition to
doc/aadb.sql and sql_update.php3

4) modify modedit.php3 script in your module directory - this script is
called after 'Add xy module' is pressed so there should be basic
module settings/creation options (as we already know from 'Slice
Admin' - slicedit.php3).

5) modify index.php3 script, which is the script, which apears after
user selects the module from 'Module selectbox' (for 'slice' module
such page is Item Manager.

6) insert new language file for the module to include/ directory (just
like en_poll_lang.php3), if you want to use module specific texts
(you probably will) (Note: all language files must be in include/
directory)

Done - module is created.

Before we go to detailed description of the steps, we have to mention
some facts, which maight be confusing.
I say, that slices are just on of the modules. That's true, but from
historical reasons there are some differences:
- the code for slice is not placed in module/ directory - it is placed
in admin/ and include/ directory instead
- name of slice configuration file is not modedit.php3, but it is
called slicedit.php3
- the id of the slice is hold in $slice_id variable. Better name for
this variable is module_id (as we use it in other modules). For now
just note, that the module_id is exactly the same as slice_id.

Let's describe the module creation steps in more detail (I will use (non
existant) 'poll' module as an example. Substitute all 'poll' words with
the name of your module, of course):

ad 1) copy module_TEMPLATE
--------------------------
In module_TEMPLATE directory are templates for all interesting scripts,
which we need for new module. So, create new directory (modules/poll/)
and copy there all files from modules/module_TEMPLATE. As steted abobe,
name of the new directory sholud be the same as the name of module.

ad 2) add module to constants.php3
----------------------------------
The only cyhange, which is need in constants.php3 script is to add new
record into $MODULES array. The array looks like:

$MODULES=array('S'=>array('name' => 'slice',
'directory' => AA_INSTAL_URL ."admin/",
'table' => 'slice',
'hide_create_module' => 1),
'W'=>array('name' => 'Site',
'directory' => AA_INSTAL_URL ."modules/site/",
'table' => 'site'),
'A'=>array('name' => 'MySQL Auth',
'directory'=>AA_INSTAL_URL ."modules/mysql_auth/"),
'table' => 'module',

'hide_create_module' => 1),
'J'=>array('name' => 'Jump inside AA control panel',
'directory' => AA_INSTAL_URL ."modules/jump/",
'table' => 'jump'));

There we see listed four modules in the example above. Each module is
identified by a letter. Let's choice any unused letter for new module -
we choose letter 'P' for poll module for example.

There are four values for each module:
- name - just a name of module as will be listed on 'Add module' page,
for example.
- directory - the name of directory, where index.php3 for this module is
stored (index.php3 script is the one, which will be
executed after user selects the module instance from
'Module selectbox' in admin interface). It is good idea to
specify the directory using AA_INSTAL_URL constant
- table - table parameter is just optional. You can specify main
database table of the module, so then you can call
GetModuleInfo() function in order to fill an info_array by
the values specific for selected module:
$poll_info = GetModuleInfo($module_id,'P');
Now you can access $poll_info['number_of_options'],
$poll_info['title'], ... when 'number_of_options' and 'title'
are fields of poll table.
- hide_create_module - set this optional option to true, if you want to
not show the module on 'Add module' page. This
option will be false for most modules.

The record to the $MODULES array for poll module could looks like:

'P' => array( 'name' => 'Poll',
'directory' => AA_INSTAL_URL ."modules/poll/",
'table' => 'poll'),


ad 3) create tables
-------------------
You will probably need the database table(s) for your module. Create it
in database and the table definition add to both:

a) doc/aadb.sql (used for new creation of new databases)

b) sql_updata.php3 script (used for database upgrades)

For clarity, prefix the new table names by the name of module (just like
table poll, poll_options or poll_votes)


ad 4) modify modedit.php3
-------------------------
modedit.php3 is the script, which is called when user on 'Add module'
page click on 'Add' for your module.

This script is used to create and modify module instance. There user
should set all main configuration options. To create such instance you
need to:

a) add a record into 'module' table (and maybe to module specific
table, just like 'poll', ...)
b) assign permissions for the module

ad a) add record into 'module' table
Module table is generalized version of slice table any module
instance (including slices) must have its recocord in module table.
The table have the following fields:

id char(16) NOT NULL,
# world wide unique module instance id. There we store packed
version of 32-digit hexadecimal number (you probably already
know
it from slices and its displaying
(<!--#include
virtual="/apc-aa/slice.php3?slice_id=763511f38a9b960c8e7a99f765e89ff9"
-->)).
The id is there stored packed to 16 characters long string by the
q_pack_id($module_id) function. If you are creating new module
instance, the new module_id should be generated by new_id() (both
functions in /include/util.php3 file). This id is foreign key for
module specific tables (such as poll table), where more
information in the instance is stored.

name char(100) NOT NULL,
# name to be displayed in 'Module selectbox' in admin interface
(Switch to:). From historical reasons it duplicates slice.name
for modules of 'slice' ('S') type

deleted smallint(5),
# boolean value to mark deleted modules. For new module you will
set it to '0'. From historical reasons it duplicates
slice.deleted for modules of 'slice' ('S') type

type char(16),
# module type - 'S' for slice, 'P' for polls (see already described
$MODULES variable in /include/constants.php3)

slice_url varchar(255),
# URL where user could view the module instance, if it is possible
for your module type. This is the url where user jumps after
(s)he click on 'View' in upper navigation bar in admin interface.

lang_file varchar(50),
# used language file for this module instance. Language files are
located in include directory (en_poll_lang.php3,
cz_poll_lang.php3) and they are described in paragraph 6)

created_at bigint(20),
# timestemp of module instance creation. We use unix timestamps -
use include/util.php3 funtion now(). This field should not be
user editable.

created_by varchar(255),
# user id of logged user. The id could be number (if you are using
SQL based permissons) or string like 'uid=honza,ou=People,ou=AA'
(if you are using LDAP permission system. In both cases you will
get such number in $auth->auth["uid"] object variable.

owner varchar(16),
# owner is the link (foreign key) to 'owner' database table

flag int(11) default '0'
# just a module flag. Not used yet. Fill it by '0'.

ad b) assign permissions for the module
The permission to the new instance will use the same functions as the
slice
- it will use AddPermObject($module_id, "slice"). The "slice" is
there from historical reasons and in fact much better name would
be "module", but we MUST use the "slice". Do NOT use any other
string then 'slice'!!!
- Note: you can (and in fact you should) redefine the meaning of
permission letters in permission string for the module (see
/include/perm_core.php3)
- If you want to assign some permissions to specified user, use
AddPerm($user_id, $module_id, 'slice', $perm), where $user_id is
the id described in section a) by the created_by field (see
above) and $perm is the permission letter(s) we mentioned in
'Note' above.
- If you do not assign any permission to any user, only superadmins
of AA will see the module instance in his 'Module selectbox' and
will be able to change it.


The admin interface of modedit.php3 should be inspired by the interface
of 'Slice Admin' (slicedit.php3). There should be upper navigation bar
(which could be slightly modified to better fit your module - see
navbar.php3) and possibly left navigation menu, if you need to split the
module configuration to more than one page.


ad 5) modify index.php3
-----------------------
index.php3 is the script, which apears after user selects the module
from 'Module selectbox'. The admin interface should be inspired by 'Item
Manager' for slice module. This is the main administration page for the
module - most users will probably have the permission to access this
page and only a few administrators will have the permission to access
configuration page - modedit.php3.


ad 6) create language file
--------------------------
Create the language file, where you will store all texts you use in
module. The language file should be named like en_poll_lang.php3,
cz_poll_lang.php3, ... (<language>_<module>_lang.php3). The language
file MUST be stored in include/ directory (just like all other language
files). The name of this file is filled in module.lang_file table field
as described in section 4).

In the language you can define as many language constants as you want,
but you MUST there define the LANG_FILE constant, where you fill the
name of language file:

define("LANG_FILE", "en_poll_lang.php3");

All others language constants are up to you.


Notes:
------
- You can create any file in your module directory, of course. If you
will use functions, prefix its name by Mod<module letter>_, so use
ModP_GetName(), ModP_Display(), ... functions, for example.
- It is good Idea to consult the features of new module on
apc-aa-general mailinglist, before you will start the
programming.
- Please, commit all created modules to CVS (ask us for write
permissions) or send the code to AA administrator.
- Write documentation for the module in order others would be able to
use it.

The coding standards are documented in doc/coding.html

We are moving to use phpDoc, the manual for this is at http://phpdoc.org/docs/HTMLframesConverter/default/phpDocumentor/tutorial_phpDocumentor.howto.pkg.html, its pretty comprehensive, and there is a need for a brief version that shows how we use it - any volunteers!

Here are some hints on debugging APC-AA,
<ol>
<li>Run the same query appending: ?errcheck=1&nocache=1<br>errcheck=1 will activate checks in a few places to make sure assumptions the code is making are valid. Sometimes this helps. It also occasional generates false warnings, especially about trying to pack invalid ids.
<br>nocache=1 will make sure that fresh data is generated rather than old stuff from the cache.
<li>Add: &debug=1
<br>This will cause lots of debugging info to be reported, if the problem is with {...} expansion look for lines starting Unaliasing, Expanding, Expanded and Continuing
<li>If the problem is timeouts, add: &debugtimes=1&time_limit=1000
<br>time-limit will extend the time in view.php3, (but not elsewhere yet)
<br>debugtimes will make every debug line report at what timestamp it was run, this will help narrow the problem down.
<br>(Note: There *have* been problems with regular expressions and long strings - suspect "ereg" and replace with preg_match.)
<li>If none of this helps, Post the url to apc-aa-coders@sourceforge.net (or apc-aa-general@sourceforge.net if you aren't on apc-aa-coders)
</ol>
Unfortunately , I haven't been able to track down any kind of symbolic debugger for PHP, so it doesn't appear to be possible to do the usual ways of debugging code ....
A work-around allowing to use the POST method for sending form data to a .shtml page is in the post2shtml.php3 file. See the comments in this file. The concept of Tagged IDS is simple - when we store an id in a field, we sometimes want to say something about it. the idea came from the directional/bidirectional links which in fact are not stored like that, but are used internally to store one or two uni-directional links.

A tagged id consists of some string followed by 24-32 hex digits. (It should be 32, but there are some buggy shorter ids due to old bugs in apc-aa). Typically the string will be a single letter g-zA-Z or a punctuation character.

Tagged id's may not be supported everywhere yet. They are supported ....

In zids.php3, which means that most other places in the code can trivially support them transparently.

In the Slice Admin -> Fields you can set a field to Relational Window, and then use hte parameter wizzard to set which buttons to use (a set of letters matching the values of the tag), then add an extra parameter (not yet supported by the wizzard) that refers to a table.

The table is in the $tps array, defined in itemfunc.php3, if you want to use anything other than the two standard ones "AMB" (Add, Mutual, Backwards) and GYR (Good, OK, Bad) then you need to somewhere in your code do something lke

$GLOBALS[tps][MyTable] => array (
G => array ( prefix => 'Good:', tag => 'x', str => _m("Good") ),
Y => array ( prefix => 'OK :', tag => 'y', str => _m("OK") ),
R => array ( prefix => 'Bad :', tag => 'z', str => _m("Bad") ));

In the Relational window, if you have specified a table, then it will be shown as buttons - just the ones picked in the second parameter.

THIS USED TO WORK, BUT SOME CHANGE TO THE CODE BY SOMEONE ELSE HAS BROKEN IT,, AND I DON'T HAVE TIME TO FIX IT.

Note that the "tag" from this field is what is stored.

You can then use this tagged field in many ways, for example it can form part of a search string, to look for only "Good" links, or you could use a switch statement to figure out how to use it.

You should NEVER have to write code in your site to strip the tag away from the value, for example if you pass a tagged id to e.g.
view.php3?vid=123&cmd[123]=x-123-z1234567890abcdef1234567890abcdef
then view.php3 SHOULD understand this correctly as refering to item 1234567890abcdef1234567890abcdef

A new pseudo-field is created idtag........... contains the tag anywhere that GetItemContent is used to get the fields (i.e. should be everywhere). So you can put {switch({idtag...........})x:GOOD} into your code.

 

This FAQ interface was developed by Jason at Commons.ca

APC: Internet and ICTs for social justice and development APC ActionApps is a free software content management system initiated by the Association for Progressive Communications (APC)
APC - Internet and ICTs for social justice and development